package com.exploadingelephants.engine;

import java.io.FileNotFoundException;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;
import ch.exploadingelephants.graph.DotColor;
import ch.exploadingelephants.graph.MachineGraph;
import ch.exploadingelephants.graph.RBBifurcationToken;
import ch.exploadingelephants.graph.WriterToken;
import ch.exploadingelephants.model.ConveyorDirection;
import ch.exploadingelephants.model.EndItem;
import ch.exploadingelephants.model.Level;
import ch.exploadingelephants.model.Machine;
import ch.exploadingelephants.model.StartItem;

import com.exploadingelephants.util.LevelIO;

/**
 * @author Sandro De Zanet
 * 
 */
public class LevelActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	try {
	    LevelIO.storeLevel(this, createFirstLevel());
	    LevelIO.storeLevel(this, createSecondLevel());
	    LevelIO.storeLevel(this, createThirdLevel());
	    LevelIO.storeLevel(this, createFourthLevel());
	    LevelIO.storeLevel(this, createFifthLevel());
	    LevelIO.storeLevel(this, createSixthLevel());
	    LevelIO.storeLevel(this, createRCCarsLevel());
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	}

	RelativeLayout layout = new RelativeLayout(this);

	List<Level> levels = LevelIO.loadAllLevels(this);
	Button last = null;
	int id = 10;
	for (final Level level : levels) {
	    Button levelButton = new Button(this);
	    levelButton.setId(id++);

	    levelButton.setText(level.getTitle());

	    levelButton.setOnClickListener(new OnClickListener() {

		public void onClick(View v) {
		    Intent intent = new Intent(LevelActivity.this,
			    MachineActivity.class);
		    intent.putExtra(MachineActivity.LEVEL_EXTRA_KEY, level);
		    LevelActivity.this.startActivity(intent);
		}
	    });

	    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
		    RelativeLayout.LayoutParams.WRAP_CONTENT,
		    RelativeLayout.LayoutParams.WRAP_CONTENT);
	    if (last != null) {
		lp.addRule(RelativeLayout.BELOW, last.getId());
	    } else {
		lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
	    }
	    layout.addView(levelButton, lp);

	    last = levelButton;
	}

	Button levelEditorButton = new Button(this);
	levelEditorButton.setId(id++);
	levelEditorButton.setText("Level Editor");
	RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
		RelativeLayout.LayoutParams.WRAP_CONTENT,
		RelativeLayout.LayoutParams.WRAP_CONTENT);
	params.addRule(RelativeLayout.BELOW, last.getId());
	layout.addView(levelEditorButton, params);

	levelEditorButton.setOnClickListener(new OnClickListener() {

	    public void onClick(View v) {
		Intent intent = new Intent(LevelActivity.this,
			LevelEditorActivity.class);
		LevelActivity.this.startActivity(intent);
	    }
	});

	setContentView(layout);
    }

    /**
     * @return
     */
    private static Level createFirstLevel() {
	Machine machine = new Machine(5, 5);
	machine.set(2, 0, new StartItem());
	machine.set(2, 4, new EndItem());

	MachineGraph graph = new MachineGraph();
	graph.getStart().connect(graph.getEnd());

	Level level = new Level("robotoast", false);
	level.setTitle("Robotoast");
	level.setDescription("Move robots from the entrance (top) to the exit (bottom)!");
	level.setMachine(machine);
	level.setSolution(graph);

	return level;
    }

    /**
     * @return
     */
    private Level createSecondLevel() {
	Machine machine = new Machine(5, 5);
	machine.set(2, 0, new StartItem());
	machine.set(2, 4, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb = new RBBifurcationToken(ConveyorDirection.SOUTH);
	graph.getStart().connect(rb);
	rb.setBlue(graph.getEnd());
	rb.setRed(graph.getNirvana());
	rb.setEmpty(graph.getNirvana());

	Level level = new Level("robocoffee", false);
	level.setTitle("Robocoffee");
	level.setDescription("If a robot's string starts with blue, accept. Otherwise, reject!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }

    /**
     * @return
     */
    private Level createThirdLevel() {
	Machine machine = new Machine(7, 7);
	machine.set(3, 0, new StartItem());
	machine.set(3, 6, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb1 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb2 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb3 = new RBBifurcationToken(ConveyorDirection.SOUTH);

	graph.getStart().connect(rb1);
	rb1.setBlue(rb2);
	rb1.setRed(rb1);
	rb1.setEmpty(graph.getNirvana());

	rb2.setBlue(rb3);
	rb2.setRed(rb2);
	rb2.setEmpty(graph.getNirvana());

	rb3.setBlue(graph.getEnd());
	rb3.setRed(rb3);
	rb3.setEmpty(graph.getNirvana());

	Level level = new Level("robolamp", false);
	level.setTitle("Robolamp");
	level.setDescription("ACCEPT: if there are three or more blues!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }

    /**
     * @return
     */
    protected Level createFourthLevel() {
	Machine machine = new Machine(5, 5);
	machine.set(2, 0, new StartItem());
	machine.set(2, 4, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb = new RBBifurcationToken(ConveyorDirection.SOUTH);
	graph.getStart().connect(rb);
	rb.setBlue(rb);
	rb.setRed(graph.getNirvana());
	rb.setEmpty(graph.getEnd());

	Level level = new Level("robofish", false);
	level.setTitle("Robofish");
	level.setDescription("ACCEPT: if a robot contains NO red!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }

    /**
     * 
     */
    private Level createFifthLevel() {
	Machine machine = new Machine(9, 9);
	machine.set(4, 0, new StartItem());
	machine.set(4, 8, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb1 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb2 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb3 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	graph.getStart().connect(rb1);

	rb1.setBlue(rb2);
	rb1.setRed(rb3);
	rb1.setEmpty(rb3);

	rb2.setRed(rb3);
	rb2.setBlue(graph.getNirvana());
	rb2.setEmpty(graph.getEnd());

	rb3.setBlue(rb2);
	rb3.setRed(graph.getNirvana());
	rb3.setEmpty(graph.getEnd());

	Level level = new Level("robobugs", false);
	level.setTitle("Robobugs");
	level.setDescription("ACCEPT: if the tape has only alternating colors!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }

    /**
     * @return
     */
    protected Level createSixthLevel() {
	Machine machine = new Machine(9, 9);
	machine.set(4, 0, new StartItem());
	machine.set(4, 8, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb1 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb2 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	RBBifurcationToken rb3 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	graph.getStart().connect(rb1);

	rb1.setBlue(rb2);
	rb1.setRed(rb1);
	rb1.setEmpty(graph.getNirvana());

	rb2.setRed(rb1);
	rb2.setBlue(rb3);
	rb2.setEmpty(graph.getNirvana());

	rb3.setBlue(rb3);
	rb3.setRed(rb1);
	rb3.setEmpty(graph.getEnd());

	Level level = new Level("robocats", false);
	level.setTitle("Robocats");
	level.setDescription("ACCEPT: if the tape ends with two blues!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }

    /**
     * 
     */
    private Level createRCCarsLevel() {
	Machine machine = new Machine(5, 5);
	machine.set(2, 0, new StartItem());
	machine.set(2, 4, new EndItem());

	MachineGraph graph = new MachineGraph();
	RBBifurcationToken rb1 = new RBBifurcationToken(ConveyorDirection.SOUTH);
	graph.getStart().connect(rb1);

	WriterToken redWriter = new WriterToken(DotColor.RED,
		ConveyorDirection.SOUTH);
	WriterToken blueWriter = new WriterToken(DotColor.BLUE,
		ConveyorDirection.SOUTH);

	rb1.setRed(redWriter);
	rb1.setBlue(blueWriter);
	rb1.setEmpty(graph.getEnd());
	redWriter.connect(graph.getEnd());
	blueWriter.connect(graph.getEnd());

	Level level = new Level("rccars", true);
	level.setTitle("RC Cars!");
	level.setDescription("OUTPUT: The input, but with the first symbol at the end!");
	level.setMachine(machine);
	level.setSolution(graph);
	return level;
    }
}
